using System;
using System.Collections.Generic;
using System.IO;
using Config;
using Cysharp.Threading.Tasks;
using Data;
using Entity;
using Entity.Monster;
using GameTime;
using Map.MapObject;
using MoonFramework.Scripts.Event;
using MoonFramework.Scripts.Pool;
using MoonFramework.Scripts.Tool;
using MoonFramework.Scripts.Tool.System.Setting;
using MoonFramework.Scripts.Tool.Timer;
using Tool;
using Tool.Name;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Profiling;
using Random = UnityEngine.Random;

namespace Map
{
    public class BaseMapBlock : MonoBehaviour
    {
        private bool _isActive;
        private float _timeLimit;
        public Vector2Int BlockIndex;
        private Dictionary<ulong, BaseMapObject> _mapObjects;
        private Dictionary<ulong, MonsterObject> _aiObjects;
        private Dictionary<ulong, MapObjectData> _destroyMapObjectList;
        public MapBlockData MapBlockData { get; private set; }
        public bool IsAllForest { get; private set; }
        public bool IsInitialized { get; private set; }

        public void Init(Vector3 centerPosition, bool isAllForest,Vector2Int BlockIndex,
            MapBlockData mapBlockData)
        {
            _timeLimit = ConfigManager.Instance.GetConfig<MapConfig>(ConfigName.Map, 0).timeLimit;
            this.BlockIndex = BlockIndex;
            IsAllForest = isAllForest;
            this.MapBlockData = mapBlockData;
            _destroyMapObjectList = new();
            _mapObjects = new (mapBlockData.MapBlockMapObjects.Count);
            _aiObjects = new (mapBlockData.MapBlockAIObjects.Count);
            _aiPosDic = new();
            IsInitialized = true;
            foreach (var item in mapBlockData.MapBlockMapObjects.Values)
            {
                if (item.DestroyDays > 0) _destroyMapObjectList.TryAdd(item.ID, item);
            }
            
            EventCenter.Instance.Register(EventName.OnMorning);
            EventCenter.Instance.SendCommand(EventName.OnMorning, OnMorning);
        }
        
        /// <summary>
        /// 动态定时器触发地图清理
        /// </summary>
        private async void Dispose()
        {
            Debug.Log(1);
            try
            {
                MapManager.Instance.UpdateEvent(BlockIndex);
                Debug.Log($"Before: {Profiler.GetTotalAllocatedMemoryLong() / 1024} KB");
                AsyncOperation asyncOp = Resources.UnloadUnusedAssets();
                while (!asyncOp.isDone) await UniTask.Yield(); //等待卸载完成
                Debug.Log($"After: {Profiler.GetTotalAllocatedMemoryLong() / 1024} KB");
            }
            catch
            {}
        }

        public void SetActive(bool active)
        {
            if (_isActive == active) return;
            _isActive = active;
            gameObject.SetActive(_isActive);

            //从对象池中拿出所有物体
            if (_isActive)
            {
                //处理地图对象
                foreach (var item in MapBlockData.MapBlockMapObjects.Values)
                {
                    InitMapObject(item).Forget();
                }
                //处理AI对象
                foreach (var item in MapBlockData.MapBlockAIObjects.Values)
                {
                    InitAIObject(item).Forget();
                }
            }
            else
            {
                foreach (var obj in _mapObjects.Values) 
                    obj.gameObject.MoonGameObjPushPool();
                foreach (var obj in _aiObjects.Values)
                    obj.Destroy();
                _mapObjects.Clear();
                _aiObjects.Clear();
                Timer.Instance.AddTask(Dispose, TimeSpan.FromSeconds(_timeLimit), 1);
            }
        }

        #region AI
        /// <summary>
        /// 初始化ai
        /// </summary>
        private async UniTaskVoid InitAIObject(MapObjectData aiObjectData)
        {
            //实例化物体
            var aiConfig = ConfigManager.Instance.GetConfig<AIConfig>(ConfigName.AI, aiObjectData.configID);
            var go = await this.MoonGameObjGetPool(Path.Combine("AI", aiConfig.name)) as GameObject;
            if (go!.TryGetComponent<MonsterObject>(out var aiObject))
            {
                go.transform.SetParent(transform);
                aiObjectData.position = aiObjectData.position == Vector3.zero ? GetAIRandomPoint(aiConfig.MapVertexType) : aiObjectData.position;
                var aiViewController = go.GetComponent<ActorViewController>();
                aiViewController.Init();
                aiObject.Init(this, aiObjectData);
                _aiObjects.TryAdd(aiObjectData.ID, aiObject); 
            }
        }
        
        private Dictionary<Tuple<int, MapVertexType>, Vector3> _aiPosDic;

        private int preForest = -1, preMarsh = -1;
        
        /// <summary>
        /// 获取AI可以到达的随机坐标
        /// </summary>
        public Vector3 GetAIRandomPoint(MapVertexType mapVertexType)
        {
            List<MapVertex> vertices = mapVertexType switch
            {
                MapVertexType.Forest => MapBlockData.ForestMapVertices,
                MapVertexType.Marsh => MapBlockData.MarshMapVertices,
                _ => null
            };
            if(vertices.Count == 0) return Vector3.zero; //递归出口
            
            int index = Random.Range(0, vertices.Count);
            switch (mapVertexType)
            {
                case MapVertexType.Forest when preForest == index:
                    GetAIRandomPoint(mapVertexType);
                    preForest = index;
                    break;
                case MapVertexType.Marsh when preMarsh == index:
                    GetAIRandomPoint(mapVertexType);
                    preMarsh = index;
                    break;
            }
            
            var tuple = Tuple.Create(index, mapVertexType);
            if (_aiPosDic.TryGetValue(tuple, out var pos))
                return pos == Vector3.zero ? GetAIRandomPoint(mapVertexType) : pos;
            //确保AI可以到达这个位置
            if (NavMesh.SamplePosition(vertices[index].position, out var hitInfo, 1, NavMesh.AllAreas))
            {
                _aiPosDic.Add(tuple, hitInfo.position);
                return hitInfo.position;
            }
            _aiPosDic.Add(tuple, Vector3.zero);
            // 递归查找下一个可以到达的坐标
            return GetAIRandomPoint(mapVertexType);
        }
        
        /// <summary>
        /// 因为迁移删除一个AI对象
        /// 只删除本地持有的数据，不做实际的对象删除，处理
        /// </summary>
        public void RemoveAIObjectOnTransfer(ulong id)
        {
            MapBlockData.MapBlockAIObjects.Remove(id);
            _aiObjects.Remove(id);
        }
        
        /// <summary>
        /// AI的游戏物体，数据存档等都要移除
        /// </summary>
        public void RemoveAIObject(ulong id)
        {
            MapBlockData.MapBlockAIObjects.Remove(id, out MapObjectData aiData);
            aiData.MoonObjPushPool();
            if (_aiObjects.Remove(id, out MonsterObject monsterObject))
                monsterObject.Destroy();
        }
        
        /// <summary>
        /// 因为迁移添加一个AI对象
        /// </summary>
        public void AddAIObjectOnTransfer(MapObjectData aiData, MonsterObject monster)
        {
            MapBlockData.MapBlockAIObjects.Add(aiData.ID, aiData);
            _aiObjects.Add(aiData.ID, monster);
            monster.transform.SetParent(transform);
            monster.InitOnTransfer(this);
        }
        
        /// <summary>
        /// 添加一个AI对象（是由MapManager调用）
        /// 1.玩家杀死Monster
        /// 2.早晨刷新Monster
        /// </summary>
        private void AddAIObject(MapObjectData aiData)
        {
            //添加存档信息
            MapBlockData.MapBlockAIObjects.Add(aiData.ID, aiData);
            if(_isActive) InitAIObject(aiData).Forget();   
        }   
        #endregion
        
        #region 地图对象
        /// <summary>
        /// 移除一个地图对象
        /// </summary>
        public void RemoveMapObject(ulong mapObjectID)
        {
            //数据层面移除，数据放进对象池
            MapBlockData.MapBlockMapObjects.Remove(mapObjectID, out MapObjectData mapObjectData);
            ObjPoolManager.Instance.Push(mapObjectData);
            
            //自身层面的移除
            if (_mapObjects.TryGetValue(mapObjectID, out var mapObject))
            {
                //游戏物体放进对象池
                mapObject.gameObject.MoonGameObjPushPool();
                _mapObjects.Remove(mapObjectID);
            }
            
            //通知上级在UI显示层面移除
            MapManager.Instance.RemoveMapObject(mapObjectID);
        }

        /// <summary>
        /// 添加一个地图对象（是由MapManager调用）
        /// 1.玩家丢弃物品
        /// 2.早晨刷新物品
        /// </summary>
        public void AddMapObject(MapObjectData mapObjectData)
        {
            //添加存档信息
            MapBlockData.MapBlockMapObjects.Add(mapObjectData.ID, mapObjectData);
            if (mapObjectData.DestroyDays > 0) _destroyMapObjectList.TryAdd(mapObjectData.ID, mapObjectData);
            if(_isActive) InitMapObject(mapObjectData).Forget();
        }
        
        private async UniTaskVoid InitMapObject(MapObjectData mapObjectData)
        {
            //实例化物体
            var mapObjectConfig =
                ConfigManager.Instance.GetConfig<MapObjectConfig>(ConfigName.MapObject, mapObjectData.configID);
            var go = await this.MoonGameObjGetPool(Path.Combine("MapObject", mapObjectConfig.name)) as GameObject;
            if (go!.TryGetComponent<BaseMapObject>(out var mapObject))
            {
                go.transform.SetParent(transform);
                go.transform.position = mapObjectData.position;
                mapObject.Init(this, mapObjectData.ID);
                _mapObjects.TryAdd(mapObjectData.ID, mapObject);
            }
        }
        #endregion

        //执行销毁的地图对象列表
        private static readonly List<ulong> DoDestroyMapObjectList = new();
        
        /// <summary>
        /// 早上会触发地图物品刷新
        /// </summary>
        private void OnMorning()
        {
            foreach (var item in _destroyMapObjectList.Values)
            {
                item.DestroyDays -= 1;
                if (item.DestroyDays == 0)
                {
                    DoDestroyMapObjectList.Add(item.ID);
                }
            }

            foreach (var item in DoDestroyMapObjectList)
            {
                RemoveMapObject(item);
            }
            //得到新增的地图对象数据
            List<MapObjectData> mapObjectDataList = MapManager.Instance.CreateMapObjectDataRefresh(BlockIndex);
            foreach (var mapObjectData in mapObjectDataList)
            {
                AddMapObject(mapObjectData);
            }
            
            //三天刷新一次AI
            if (TimeManager.Instance.CurDay % 3 == 0)
            {
                mapObjectDataList = MapManager.Instance.CreateAIObjectDataRefresh(MapBlockData);
                foreach (var mapObjectData in mapObjectDataList)
                {
                    AddAIObject(mapObjectData);
                }
            }
        }
        
        private void OnGameClose()
        {
            ArchiveManager.Instance.SavaBlockData(BlockIndex, MapBlockData);
        }

        public void OnCloseGameScene()
        {
            OnGameClose();
            SetActive(false);
        }
    }
}